// *************************************************************************************************
//
// MK3D Engine
// --------------------------------------
// Copyright (C) 2007-2011 Zeb (mailto: zebbey@gmail.com)
//
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
// *************************************************************************************************

#include "mk_header.h"
#include "mk_d3d9_hardware_buffer.h"
#include "mk_error.h"
#include "mk_d3d9_render_device.h"
#include "mk_render_define.h"
#include "mk_engine.h"

namespace MK3DE
{
	CD3D9VertexHardwareBuffer::CD3D9VertexHardwareBuffer() : _d3dVertexBuffer(NULL), _vertexSize(0),
		_vertexNum(0)
	{
	}

	CD3D9VertexHardwareBuffer::~CD3D9VertexHardwareBuffer()
	{
		SAFE_RELEASE(_d3dVertexBuffer);
	}

	BOOL CD3D9VertexHardwareBuffer::Create(DWORD vertexSize, DWORD vertexNum, HARDWARE_BUFFER_USAGE usage)
	{
		CD3D9RenderDevice *device = (CD3D9RenderDevice*)GetEngine()->GetRenderDevice();
		LPDIRECT3DDEVICE9 d = device->GetD3DDevice();
		DWORD d3dusage = 0;
		D3DPOOL pool = D3DPOOL_MANAGED;
		if (usage & HBU_DYNAMIC)
			d3dusage |= D3DUSAGE_DYNAMIC;
		if (usage & HBU_WRITE_ONLY)
			d3dusage |= D3DUSAGE_WRITEONLY;

		if ((usage & HBU_WRITE_ONLY) && (usage & HBU_DYNAMIC))
			pool = D3DPOOL_DEFAULT;

		HRESULT hr = d->CreateVertexBuffer((UINT)(vertexNum * vertexSize), d3dusage, 0, pool, &_d3dVertexBuffer, 0);
		MK_PROCESS_COM_ERROR(hr);

		_vertexSize = vertexSize;
		_vertexNum = vertexNum;

		return TRUE;

Exit0:
		return FALSE;
	}

	BOOL CD3D9VertexHardwareBuffer::Lock(void*& pBuffer, DWORD offset, DWORD size, LOCK_OPTION option)
	{
		DWORD d3dop = 0;
		if (option == LO_READ_ONLY)
			d3dop = D3DLOCK_READONLY;
		else if (option == LO_NO_OVER_WRITE)
			d3dop = D3DLOCK_NOOVERWRITE;
		else if (option == LO_DISCARD)
			d3dop = D3DLOCK_DISCARD;

		HRESULT hr = _d3dVertexBuffer->Lock((UINT)offset, (UINT)size, &pBuffer, d3dop);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;

Exit0:
		return FALSE;
	}

	BOOL CD3D9VertexHardwareBuffer::Unlock()
	{
		HRESULT hr = _d3dVertexBuffer->Unlock();
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	CD3D9IndexHardwareBuffer::CD3D9IndexHardwareBuffer() : _d3dIndexBuffer(NULL), _stride(0), 
		_vertexNum(0)
	{
	}

	CD3D9IndexHardwareBuffer::~CD3D9IndexHardwareBuffer()
	{
		SAFE_RELEASE(_d3dIndexBuffer);
	}

	BOOL CD3D9IndexHardwareBuffer::Create(DWORD vertexNum, INDEX_TYPE indexType, HARDWARE_BUFFER_USAGE usage)
	{
		CD3D9RenderDevice *device = (CD3D9RenderDevice*)GetEngine()->GetRenderDevice();
		LPDIRECT3DDEVICE9 d = device->GetD3DDevice();
		DWORD d3dusage = 0;
		D3DPOOL pool = D3DPOOL_MANAGED;
		if (usage & HBU_DYNAMIC)
			d3dusage |= D3DUSAGE_DYNAMIC;
		if (usage & HBU_WRITE_ONLY)
			d3dusage |= D3DUSAGE_WRITEONLY;

		if (usage & HBU_DYNAMIC)
			pool = D3DPOOL_DEFAULT;

		D3DFORMAT fmt = D3DFMT_INDEX16;
		_stride = sizeof(WORD);
		if (indexType == IT_32BIT)
		{
			fmt = D3DFMT_INDEX32;
			_stride = sizeof(DWORD);
		}

		UINT length = (UINT)(vertexNum * _stride);
		HRESULT hr = d->CreateIndexBuffer(length, d3dusage, fmt, pool, &_d3dIndexBuffer, 0);
		MK_PROCESS_COM_ERROR(hr);

		_vertexNum = vertexNum;
		return TRUE;

Exit0:
		return FALSE;
	}

	BOOL CD3D9IndexHardwareBuffer::Lock(void*& pBuffer, DWORD offset, DWORD size, LOCK_OPTION option)
	{
		DWORD d3dop = 0;
		if (option == LO_READ_ONLY)
			d3dop = D3DLOCK_READONLY;
		else if (option == LO_NO_OVER_WRITE)
			d3dop = D3DLOCK_NOOVERWRITE;
		else if (option == LO_DISCARD)
			d3dop = D3DLOCK_DISCARD;

		HRESULT hr = _d3dIndexBuffer->Lock((UINT)offset, (UINT)size, &pBuffer, d3dop);
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}

	BOOL CD3D9IndexHardwareBuffer::Unlock()
	{
		HRESULT hr = _d3dIndexBuffer->Unlock();
		MK_PROCESS_COM_ERROR(hr);

		return TRUE;
Exit0:
		return FALSE;
	}
}